package com.iwhalecloud.uncc.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 *
 * <p>
 * Title: ByteUtil
 * </p>
 * <p>
 * Description: 一些字节处理的工具函数，用于一些比较底层的基于字节的协议转换
 * </p>
 * <p>
 * Copyright: Copyright (c) 2006
 * </p>
 * <p>
 * Company:
 * </p>
 *
 * @author xioayuer
 * @version 1.0
 */
public class ByteUtil {
	private static final Logger logger = LoggerFactory.getLogger(ByteUtil.class);
	/**
	 *
	 */
	private ByteUtil() {

	}

	/**
	 * 初始化内存字节
	 *
	 * @param src
	 *            byte[]
	 * @param c
	 *            byte
	 * @param pos
	 *            int
	 * @param count
	 *            int
	 * @return byte[]
	 */
	public static byte[] memset(byte[] src, byte c, int pos, int count) {
		if (pos < 0 || pos > src.length || count <= 0) {
			return src;
		}

		if (src == null) {
			src = new byte[pos + count]; // 也必须通过返回参数来获取值
		}

		for (int i = 0; i < count && pos + i < src.length; i++) {
			src[pos + i] = c;
		}

		return src;
	}

	/**
	 * 内存字节拷贝
	 *
	 * @param dest
	 *            byte[]
	 * @param pos
	 *            int
	 * @param src
	 *            byte[]
	 * @param size
	 *            int
	 * @return byte[]
	 */
	public static byte[] memcpy(byte[] dest, int pos, byte[] src, int size) {
		if (size >= 0) {
			size = size > dest.length ? dest.length : size;
			System.arraycopy(src, 0, dest, pos, size);
		}
		return dest;
	}

	/**
	 * 字节头部填充
	 *
	 * @param src
	 *            byte[]
	 * @param length
	 *            int
	 * @param fill
	 *            byte
	 * @return byte[]
	 */
	public static byte[] fillHead(byte[] src, int length, byte fill) {
		if (src.length >= length) {
			return src;
		}

		byte[] dest = new byte[length];
		ByteUtil.memset(dest, fill, 0, length);
		ByteUtil.memcpy(dest, length > src.length ? length - src.length : 0,
				src, src.length);
		return dest;
	}

	/**
	 * 字节尾部填充
	 *
	 * @param src
	 *            byte[]
	 * @param length
	 *            int
	 * @param fill
	 *            byte
	 * @return byte[]
	 */
	public static byte[] fillTail(byte[] src, int length, byte fill) {
		if (src.length >= length) {
			return src;
		}

		byte[] dest = new byte[length];
		ByteUtil.memset(dest, fill, 0, length);
		ByteUtil.memcpy(dest, 0, src, src.length);
		return dest;
	}

	/**
	 * 插入字节到目标字节数组，使用者须保证目标空间足够，后面的字节被覆盖
	 *
	 * @param dest
	 *            byte[]
	 * @param src
	 *            byte[]
	 * @param pos
	 *            int
	 * @param length
	 *            int
	 * @return byte[]
	 */
	public static byte[] insert(byte[] dest, byte[] src, int pos, int length) {
		if (length > dest.length) {
			length = dest.length;
		}

		for (int i = 0; i < pos + length; i++) {
			if (i >= pos && i < pos + length) {
				if (i + length < dest.length) {
					dest[i + length] = dest[i];
				}
				if (i - pos < src.length) {
					dest[i] = src[i - pos];
				}
			}
		}

		return dest;
	}

	/**
	 * 复制字节到目标字节数组，使用者须保证目标空间足够
	 *
	 * @param dest
	 *            byte[]
	 * @param src
	 *            byte[]
	 * @param pos
	 *            int
	 * @param length
	 *            int
	 * @return byte[]
	 */
	public static byte[] copyto(byte[] dest, byte[] src, int pos, int length) {
		if (length > src.length) {
			length = src.length;
		}

		if (dest == null || dest.length < pos + length) {
			byte[] buf = new byte[pos + length];
			memcpy(buf, 0, dest, pos);
			dest = buf;
		}

		for (int i = 0; i < length; i++) {
			dest[pos + i] = src[i];
		}

		return dest;
	}

	/**
	 * 从源字节数组指定位置复制字节到目标字节数组，使用者须保证目标空间足够
	 *
	 * @param dest
	 *            byte[]
	 * @param src
	 *            byte[]
	 * @param pos
	 *            int
	 * @param length
	 *            int
	 * @return byte[]
	 */
	public static byte[] copyfrom(byte[] dest, byte[] src, int pos, int length) {
		if (length > src.length) {
			length = src.length;
		}

		if (dest == null || dest.length < length) { // 只能通过返回参数返回，无法通过入参返回，与C语言不同。
			dest = new byte[length];
		}

		for (int i = 0; i < length; i++) {
			dest[i] = src[pos + i];
		}

		return copy(dest, 0, length); // 返回一个新建数组
	}

	/**
	 * 删除字节内容，返回删除后的内容
	 *
	 * @param src
	 *            byte[]
	 * @param pos
	 *            int
	 * @param length
	 *            int
	 * @return byte[] 删除一些字节的新数组
	 */
	public static byte[] delete(byte src[], int pos, int length) {
		if (src == null) {
			return null;
		}

		if (pos > src.length || pos < 0 || length < 0) { // 非法参数
			return src;
		}

		if (pos + length > src.length) {
			length = src.length - pos;
		}

		byte[] dest = new byte[src.length - length];
		for (int i = 0; i < src.length; i++) {
			if (i - pos >= 0 && i - pos < length) {
				continue;
			}
			dest[i] = src[i];
		}
		return dest;
	}

	/**
	 * 字节拷贝，返回拷贝内容
	 *
	 * @param src
	 *            byte[]
	 * @param pos
	 *            int
	 * @param size
	 *            int
	 * @return byte[]
	 */
	public static byte[] copy(byte[] src, int pos, int size) {
		if (pos < 0 || pos > src.length || size <= 0) { // 非法参数
			return null;
		}

		byte[] dest = new byte[src.length - pos < size ? src.length - pos
				: size];
		for (int i = 0; i < size && pos + i < src.length; i++) {
			dest[i] = src[pos + i];
		}

		return dest;
	}

	/**
	 * 转换成16进制的格式
	 *
	 * @param length
	 *            int
	 * @param hexlen
	 *            int
	 * @param fillhead
	 *            byte
	 * @return byte[]
	 */
	public static byte[] toHexBytes(int length, int hexlen, byte fillhead) {
		if (hexlen <= 0) {
			return null;
		}

		byte dest[] = new byte[hexlen];
		ByteUtil.memset(dest, fillhead, 0, hexlen);
		byte[] src = Integer.toHexString(length).getBytes();
		System.arraycopy(src, 0, dest, hexlen - src.length > 0 ? hexlen
				- src.length : 0, src.length);

		return dest;
	}

	/**
	 *
	 * @param b
	 *            byte[]
	 * @return int
	 */
	public static int bytes2int(byte[] b) {
		// byte[] b=new byte[]{1,2,3,4};
		int mask = 0xff;
		int temp = 0;
		int res = 0;
		for (int i = 0; i < 4; i++) {
			res <<= 8;
			temp = b[i] & mask;
			res |= temp;
		}
		return res;
	}

	public static int bytes2intForlittleEndian(byte[] b) {
		// byte[] b=new byte[]{1,2,3,4};
		int mask = 0xff;
		int temp = 0;
		int res = 0;
		for (int i = 3; i >=0; i--) {
			res <<= 8;
			temp = b[i] & mask;
			res |= temp;
		}
		return res;
	}
	/**
	 *
	 * @param b
	 *            byte
	 * @return String
	 */
	public static String byte2hex(byte b) {
		String hex = Integer.toHexString((int) b & 0xff);
		if (hex.length() == 1) {
			hex = "0" + hex;
		}
		return hex;
	}

	/**
	 *
	 * @param hex
	 *            String
	 * @return byte
	 */
	public static byte hex2byte(String hex) {
		return (byte) (Integer.parseInt(hex, 16) & 0xff);
	}

	/**
	 *
	 * @param hex
	 *            String
	 * @return byte[]
	 */
	public static byte[] hex2bytes(String hex) {
		if (hex == null || hex.trim().length() == 0) {
			return null;
		}

		byte[] dest = new byte[hex.length() / 2];
		for (int i = 0; i < hex.length() / 2; i++) {
			String h = hex.substring(2 * i, 2 * i + 2);
			dest[i] = hex2byte(h);
		}

		return dest;
	}

	/**
	 *
	 * @param bytes
	 *            byte[]
	 * @return String
	 */
	public static String bytes2hex(byte[] bytes) {
		StringBuffer sb = null;
		if (bytes == null || bytes.length == 0) {
			return null;
		}

		sb = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			sb.append(byte2hex(bytes[i]));
		}

		return sb.toString();
	}

	/**
	 *
	 * @param num
	 *            int
	 * @return byte[]
	 */
	public static byte[] int2bytes(int num) {
		byte[] b = new byte[4];
		// int mask=0xff;
		for (int i = 0; i < 4; i++) {
			b[i] = (byte) (num >>> (24 - i * 8));
			// logger.info(Integer.toHexString((int)b[i]));
		}
		return b;
	}

	/**
	 *
	 * @param num
	 *            int
	 * @return byte[]
	 */
	public static byte[] short2bytes(int num) {
		num &= 0xffff;
		byte[] b = new byte[2];
		// int mask=0xff;
		for (int i = 0; i < 2; i++) {
			b[i] = (byte) (num >>> (8 - i * 8));
			//logger.info(Integer.toHexString((int)b[i]));
		}
		return b;
	}

	/**
	 * byte2short
	 *
	 * @param b
	 *            byte[]
	 * @return int
	 */
	public static int byte2short(byte[] b) {
		int mask = 0xff;
		int temp = 0;
		int res = 0;
		for (int i = 0; i < 2; i++) {
			res <<= 8;
			temp = b[i] & mask;
			res |= temp;
		}
		return res;
	}

	/**
	 *
	 * @param h
	 *            int
	 * @return int
	 */
	public static int htonl(int h) {
		int nl = 0;
		int b = 0;

		for (int i = 0; i < 4; i++) {
			b = (h << (24 - i * 8)) & 0xff000000;
			// logger.info(Integer.toHexString(b));
			// logger.info(Integer.toHexString(b >> (i * 8)));
			nl = nl + (b >> (i * 8));
		}

		// /logger.info(Integer.toHexString(nl));
		return nl;
	}

	public static byte[] htonlbytes(int h) {
		// return int2bytes(htonl(h));
		return int2bytes(h);
	}

	/**
	 *
	 * @param h
	 *            int
	 * @return int
	 */
	public static int htons(int h) {
		int ns = 0;
		int b = 0;
		for (int i = 0; i < 2; i++) {
			b = (h << (8 - i * 8)) & 0xff00;
			// logger.info(Integer.toHexString(b));
			// logger.info(Integer.toHexString(b >> 8));
			ns = ns + (b >> (i * 8));
		}

		// logger.info(Integer.toHexString(ns));
		return ns;
	}

	public static byte[] htonsbytes(int h) {
		// return short2bytes(htons(h));
		return short2bytes(h);
	}

	/**
	 *
	 * @param n
	 *            int
	 * @return int
	 */
	public static int ntohl(int n) {
		return htonl(n);
	}

	public static int nbytestohl(byte[] n) {
		// return ntohl(bytes2int(n));
		return bytes2int(n);
	}

	public static int ntohs(int n) {
		return htons(n);
	}

	public static int nbytestohs(byte[] n) {
		// return ntohs(byte2short(n));
		return byte2short(n);
	}

	// /**
	// * getZteIHLRChecksum
	// * @param msg char[]
	// * @return char[]
	// */
	// public static char[] getZteIHLRChecksum(char[] msg) {
	// int i = 0, j = 0;
	// char[] checksum = new char[4];
	//
	// for (i = 0; i < msg.length / 4; i++) {
	// for (j = 0; j < 4; j++) {
	// checksum[j] ^= msg[i * 4 + j];
	// }
	// }
	//
	// for (j = 0; j < msg.length % 4; j++) {
	// checksum[j] ^= msg[i * 4 + j];
	// }
	//
	// for (i = 0; i < 4; i++) {
	// int k = ~checksum[i] & 0xff;
	// checksum[i] = (char) k;
	// }
	//
	// StringBuffer sb = new StringBuffer();
	// for (i = 0; i < 4; i++) {
	// String s = Integer.toHexString(checksum[i] & 0xff).toUpperCase();
	// if (s.length() < 2) {
	// sb.append("0").append(s);
	// }
	// else {
	// sb.append(s);
	// }
	// }
	//
	// return sb.toString().toCharArray();
	// }

	// /**
	// * getZtePCSChecksum
	// * @param msg char[]
	// * @return char[]
	// */
	// public static char[] getZtePCSChecksum(char[] msg) {
	// int i = 0, j = 0;
	// char[] checksum = new char[4];
	//
	// for (i = 2; i < (msg.length - 8) / 4; i++) {
	// for (j = 0; j < 4; j++) {
	// checksum[j] ^= msg[i * 4 + j];
	// }
	// }
	//
	// for (i = 0; i < 4; i++) {
	// int k = ~checksum[i] & 0xff;
	// checksum[i] = (char) k;
	// }
	//
	// StringBuffer sb = new StringBuffer();
	// for (i = 0; i < 4; i++) {
	// String s = Integer.toHexString(checksum[i] & 0xff).toUpperCase();
	// if (s.length() < 2) {
	// sb.append("0").append(s);
	// }
	// else {
	// sb.append(s);
	// }
	// }
	//
	// return sb.toString().toCharArray();
	// }

	/**
	 * 为比对字节好用，显示输出格尺
	 */
	public static void showGrid() {
		for (int i = 0; i < 10; i++) {
			logger.info("0123456789");
		}
	}

	/**
	 *
	 * @param buf
	 *            byte[]
	 */
	public static void showBytes(byte[] buf) {
		if (buf == null) {
			buf = new byte[0];
		}
		String hex = "";
		byte[] s = new byte[16];
		//logger.info("[BYTES INFO] : LENGTH = " + buf.length + "(0x" + Integer.toHexString(buf.length) + ")");
		for (int i = 0; i < buf.length; i++) {
			if (i % 16 == 0) { // 行号
				hex = Integer.toHexString((i & 0xff) / 16); // hex 字符
				if (hex.length() == 1) {
					hex = "0" + hex;
				}
				logger.info("[" + hex + "]  ");
			}

			hex = Integer.toHexString(((byte) buf[i]) & 0xff); // hex 字符
			if (hex.length() == 1) {
				hex = "0" + hex;
			}
			logger.info(hex + " "); // 输出HEX
			s[i % 16] = buf[i];

			if (i != 0 && i % 8 == 7 && i % 16 != 15) { // 8 字节
				logger.info("  ");
			}

			if (i != 0 && (i % 16 == 15 || i == buf.length - 1)) { // 16字节或结束
				if (i % 16 != 15) { // 补空格
					for (int k = i % 16; k < 16; k++) {
						if (k == 7) {
							logger.info("  ");
						} else {
							logger.info("   ");
						}
					}
				}

				logger.info("  "); // 输出可打印字符
				for (int j = 0; j < i % 16 + 1; j++) {
					if (s[j] == 0 || s[j] <= ' ' || s[j] > 127) {
						s[j] = '.';
					}
				}

				logger.info("\n"); // 输出换行
			}
		}

		//logger.info("");
	}

	public static String showBytes4Log4j(byte[] buf) {
		StringBuffer sb = new StringBuffer();
		if (buf == null) {
			buf = new byte[0];
		}
		String hex = "";
		byte[] s = new byte[16];
		sb.append("[BYTES INFO] : LENGTH = " + buf.length + "(0x"
				+ Integer.toHexString(buf.length) + ")" + "\n");
		for (int i = 0; i < buf.length; i++) {
			if (i % 16 == 0) { // 行号
				hex = Integer.toHexString((i & 0xff) / 16); // hex 字符
				if (hex.length() == 1) {
					hex = "0" + hex;
				}
				sb.append("[" + hex + "]  ");
			}

			hex = Integer.toHexString(((byte) buf[i]) & 0xff); // hex 字符
			if (hex.length() == 1) {
				hex = "0" + hex;
			}
			sb.append(hex + " "); // 输出HEX
			s[i % 16] = buf[i];

			if (i != 0 && i % 8 == 7 && i % 16 != 15) { // 8 字节
				sb.append("  ");
			}

			if (i != 0 && (i % 16 == 15 || i == buf.length - 1)) { // 16字节或结束
				if (i % 16 != 15) { // 补空格
					for (int k = i % 16; k < 16; k++) {
						if (k == 7) {
							sb.append("  ");
						} else {
							sb.append("   ");
						}
					}
				}

				sb.append("  "); // 输出可打印字符
				for (int j = 0; j < i % 16 + 1; j++) {
					if (s[j] == 0 || s[j] <= ' ' || s[j] > 127) {
						s[j] = '.';
					}
					sb.append((char) s[j]);
				}

				sb.append("\n"); // 输出换行
			}
		}

		return sb.append("\n").toString();
	}

	public static byte[] toByteArray(int iSource, int iArrayLen) {
		byte[] bLocalArr = new byte[iArrayLen];
		for ( int i = 0; (i < 4) && (i < iArrayLen); i++) {
			bLocalArr[i] = (byte)( iSource>>8*i & 0xFF );
		}
		return bLocalArr;
	}



	public static String octetStringToString(String octetString)  {
		octetString=octetString.replaceAll(":","");
		byte bs[] = new byte[octetString.length() / 2];
		for (int i=0; i<octetString.length(); i+=2) {
			bs[i/2] = (byte) Integer.parseInt(octetString.substring(i, i+2), 16);
		}
		String result="";
		try {
			result = new String(bs, "UTF8");
		}catch (Exception e){

		}
		return result;
	}



	public static int[] octetStringToBytes(String value_ipar)
	{
		String[] bytes= value_ipar.split("[^0-9A-Fa-f]");
		int[] result = new int[bytes.length];
		int counter;
		for (counter = 0; counter < bytes.length; counter++)
			result[counter] = Integer.parseInt(bytes[counter], 16);
		return (result);

	}
	public static String octetStringToDate(String value_ipar,String dateFormat)
	{
		int[] bytes= octetStringToBytes(value_ipar);
		if (bytes[0] == 0)
			return (null);
		if(dateFormat==null) {
			dateFormat = "yyyy-MM-dd HH:mm:ss";
		}
		int year;
		int month;
		int day;
		int hour;
		int minute;
		int second;
		int deci_sec = 0;
		int offset = 0;
		year = (bytes[0] * 256) + bytes[1];
		month = bytes[2];
		day = bytes[3];
		hour = bytes[4];
		minute = bytes[5];
		second = bytes[6];
		if (bytes.length >= 8)
			deci_sec = bytes[7];
		if (bytes.length >= 10)
		{
			offset = bytes[9] * 60;
			if (bytes.length >= 11)
				offset += bytes[10];
			if (bytes[8] == '-')
				offset = -offset;
			offset *= 60 * 1000;
		}

		// ------------------------------------
		// Get current DST and time zone offset
		// ------------------------------------
		Calendar calendar;
		int      my_dst;
		int      my_zone;
		calendar = Calendar.getInstance();
		my_dst = calendar.get(Calendar.DST_OFFSET);
		my_zone = calendar.get(Calendar.ZONE_OFFSET);

		// ----------------------------------
		// Compose result
		// Month to be converted into 0-based
		// ----------------------------------
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, month - 1);
		calendar.set(Calendar.DAY_OF_MONTH, day);
		calendar.set(Calendar.HOUR_OF_DAY, hour);
		calendar.set(Calendar.MINUTE, minute);
		calendar.set(Calendar.SECOND, second);
		calendar.set(Calendar.MILLISECOND, deci_sec * 100);

		// ---------
		// Reset DST
		// ---------
		calendar.add(Calendar.MILLISECOND, my_dst);

		// -----------------------------------------------------------------------------------
		// If the offset is set, we have to convert the time using the offset of our time zone
		// -----------------------------------------------------------------------------------
		if (offset != 0)
		{
			int delta;
			delta = my_zone - offset;
			calendar.add(Calendar.MILLISECOND, delta);
		}
		SimpleDateFormat  df= new SimpleDateFormat(dateFormat);
		return df.format(calendar.getTime());

	}



	public static void main(String[] args) throws Exception {
		System.out.println(octetStringToFloat("9f:78:04:45:9f:60:00"));
		System.out.println(octetStringToFloat("9f:78:04:45:83:40:00"));
	}

	/***
	 * BER编码数据，9f78代表浮点数类型;04代表4字节长度，后面为真实数据
	 * @param expression
	 * @return
	 */
	public static String octetStringToFloat(String expression) {
		String floatMark="9f:78:04";
		String octetString="";
		if(expression.startsWith(floatMark)){
			octetString=expression.replace(floatMark,"").replaceAll(":","");
			//转换字节数组
			byte bs[] = hex2bytes(octetString);
			octetString=""+ByteBuffer.wrap(bs).
					order(ByteOrder.BIG_ENDIAN).getFloat();
		}
		return  octetString;
	}
}
